﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace MonoPhysics
{
    #region Interfaces et structures
    public interface IShape
    {
        RigidBody Pere { get; set; }
        BroadBox BoundaryRect { get; }
        MonoPhysics.BoundingBox BoundingBox { get; }
    }
    /// <summary>
    /// Interface décrivant les propriétes minimales d'un élément consistant (objet susceptible de provoquer des collisions) de l'univers.
    /// </summary>
    public abstract class RigidBody : Node
    {
        public delegate void PositionChangedHandler(Vector newPos, Vector oldPos);

        public MonoPhysics.MouvementType currMouvement = MonoPhysics.MouvementType.Passive;

        private bool lockY;
        private bool lockX;
        private bool sleeping;
        private StatisticArbiter sa;

        [System.Xml.Serialization.XmlIgnore]
        public bool Sleeping
        {
            get { return sleeping; }
            set { sleeping = value; }
        }

        public bool LockX
        {
            get { return lockX; }
            set { lockX = value; }
        }
        public bool LockY
        {
            get { return lockY; }
            set { lockY = value; }
        }

        public void InitArbiter(int frameLimit, int frameTolerence)
        { this.sa = new StatisticArbiter(this, frameLimit, frameTolerence); }
        public void SolveArbiter()
        {
            if (!this.sleeping)
                this.sa.Solve();
        }
        // For debug
        //public List<SegmentD> separatingEdge = new List<SegmentD>();
        // End For debug
        public List<PointD> CollisionPoints = new List<PointD>();
        public List<Vector> contactTgts = new List<Vector>();
        public bool logical = false;
        protected int and_objectGroup;
        protected int xnor_objectGroup;
        protected Vector pos;
        /// <summary>
        /// Contient les informations physiques de l'objet (vitesse, accélération, etc...).
        /// </summary>
        public abstract PhysicContext PhysicStats { get; set; }
        /// <summary>
        /// Masse de l'objet en kg.
        /// </summary>
        public abstract float M { get; set; }
        public abstract float I { get; set; }
        [System.Xml.Serialization.XmlIgnore]
        public abstract float _invI { get; }
        [System.Xml.Serialization.XmlIgnore]
        public abstract float _invM { get; }
        [System.Xml.Serialization.XmlIgnore]
        public abstract float Restitution { get; }
        public abstract float RotationGrad { get; set; }
        [System.Xml.Serialization.XmlIgnore]
        public abstract IShape Shape { get; set; }

        public virtual int And_objectGroup
        {
            get { return this.and_objectGroup; }
            set { this.and_objectGroup = value; }
        }

        public virtual int Xnor_objectGroup
        {
            get { return this.xnor_objectGroup; }
            set { this.xnor_objectGroup = value; }
        }

        [System.Xml.Serialization.XmlIgnore]
        public virtual Vector Pos
        {
            get
            { return this.pos; }
            set
            { this.pos = value; }
        }

        [System.ComponentModel.Browsable(false)]
        [System.Xml.Serialization.XmlIgnore]
        public RectangleF ShapePosDim
        { get { return new RectangleF((float)(this.Shape.BoundaryRect.min[0].value), (float)(this.Shape.BoundaryRect.min[1].value), (float)(this.Shape.BoundaryRect.max[0].value - this.Shape.BoundaryRect.min[0].value), (float)(this.Shape.BoundaryRect.max[1].value - this.Shape.BoundaryRect.min[1].value)); } }

        public virtual bool AcceptFusionWith(RigidBody rb,Edge e)
        {
            return true;
        }

        //// Objet interactif
        public abstract void FusionedWith(RigidBody r);
        public void ObjectFusion(List<PointD> pts, Vector v2, float omega2)
        {
            Vector pos = this.pos;
            this.pos = new Vector();
            ((Polygon)this.Shape).UpdatePolygoneAsFusion(pts);
            PhysicContext pc = this.PhysicStats;
            pc.V = v2 + pc.V;
            pc.AngularVitess = omega2;
            this.PhysicStats = pc;
            this.pos = pos + ((Polygon)this.Shape).NonZeroCentroid;
        }

        public abstract void DestroyBecauseFusionWith(RigidBody rb);


        protected bool hasInteractiveModeEnabled = false;
        [System.Xml.Serialization.XmlIgnore]
        public bool HasInteractiveModeEnabled
        {
            get { return this.hasInteractiveModeEnabled; }
            set { this.hasInteractiveModeEnabled = value; }
        }


        [System.Xml.Serialization.XmlIgnore]
        public PhysicEvent VanishedContactEvent,
                    VanishedCloseProximityEvent,
                    NewContactEvent,
                    PersistantContactEvent,
                    CloseProximityEvent,
                    PersistantCloseProximityEvent;

        public void IncrementalUpdateEndpoints(MonoPhysics.BroadPhase bf)
        {
            this.Shape.BoundingBox.XMin.Value.value = this.Shape.BoundaryRect.min[0].value + this.pos.X;
            bf.NotifyEndPointUpdated(this.Shape.BoundingBox.XMin);
            this.Shape.BoundingBox.XMax.Value.value = this.Shape.BoundaryRect.max[0].value + this.pos.X;
            bf.NotifyEndPointUpdated(this.Shape.BoundingBox.XMax);
            this.Shape.BoundingBox.YMin.Value.value = this.Shape.BoundaryRect.min[1].value + this.pos.Y;
            bf.NotifyEndPointUpdated(this.Shape.BoundingBox.YMin);
            this.Shape.BoundingBox.YMax.Value.value = this.Shape.BoundaryRect.max[1].value + this.pos.Y;
            bf.NotifyEndPointUpdated(this.Shape.BoundingBox.YMax);
        }
    }
    public delegate void PhysicEvent(Edge r);

    #endregion
}
